package cn.tedu.mall.seckill.service.impl;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.pojo.domain.CsmallAuthenticationInfo;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.order.service.IOmsOrderService;
import cn.tedu.mall.pojo.order.dto.OrderAddDTO;
import cn.tedu.mall.pojo.order.dto.OrderItemAddDTO;
import cn.tedu.mall.pojo.order.vo.OrderAddVO;
import cn.tedu.mall.pojo.seckill.dto.SeckillOrderAddDTO;
import cn.tedu.mall.pojo.seckill.dto.SeckillOrderItemAddDTO;
import cn.tedu.mall.pojo.seckill.model.Success;
import cn.tedu.mall.pojo.seckill.vo.SeckillCommitVO;
import cn.tedu.mall.seckill.config.RabbitMqComponentConfiguration;
import cn.tedu.mall.seckill.service.ISeckillService;
import cn.tedu.mall.seckill.utils.SeckillCacheUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class SeckillServiceImpl implements ISeckillService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @DubboReference
    private IOmsOrderService  dubboOrderService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Override
    public SeckillCommitVO commitSeckill(SeckillOrderAddDTO seckillOrderAddDTO) {
        //一.要判断当前用户是否为重复购买,从Redis中判断是否有库存
        //获取商品skuId
        Long skuId = seckillOrderAddDTO.getSeckillOrderItemAddDTO().getSkuId();
        //从SpringSecurity获得用户id
        Long userId = getUserId();
        //根据当前用户id和skuId进行重复购买的检查
        String reSeckillCheckKey = SeckillCacheUtils.getReseckillCheckKey(skuId,userId);
        //使用key来调用redis的increment()的方法
        //increment 增长,
        //1如果当前key不存在,redis会创建这个key,并保存他的值为1.如果存在,值则增1,为2..将值返回
        Long seckillTimes = stringRedisTemplate.boundValueOps(reSeckillCheckKey).increment();
        if(seckillTimes > 100){
            throw new CoolSharkServiceException(ResponseCode.FORBIDDEN,"你已经购买过该商品了,本商城秒杀禁止重复购买");
        }
        //用户没有购买过商品
        //开始检查库存
        String seckillSkuCountKey = SeckillCacheUtils.getStockKey(skuId);
        Long leftStock = stringRedisTemplate.boundValueOps(seckillSkuCountKey).decrement();
        if(leftStock < 0){
            //终止当前用户本次购买
            //将当前用户购买此商品的次数修改回0
            stringRedisTemplate.boundValueOps(reSeckillCheckKey).decrement();
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"对不起,该商品已经售罄!");
        }
        //二.秒杀订单转换成普通订单,需要使用dubbo在order模块完成
        OrderAddDTO orderAddDTO = convertSeckillOrderToOrder(seckillOrderAddDTO);
        orderAddDTO.setUserId(userId);
        //调用新增订单的方法
        OrderAddVO orderAddVO = dubboOrderService.addOrder(orderAddDTO);
        log.info("调用新增订单的方法:{}",orderAddVO);

        //三.用消息队列(RabbitMQ)的方式将秒杀成功信息保存在success表中
        //向RabbitMQ中发送Success对象,实现消息队列的方法新增success信息到数据库
        Success success = new Success();
        //将SeckillOrderItemAddDTO赋值到Success
        BeanUtils.copyProperties(seckillOrderAddDTO.getSeckillOrderItemAddDTO(),success);
        //补全缺少信息
        success.setUserId(userId);
        success.setOrderSn(orderAddVO.getSn());
        success.setSeckillPrice(seckillOrderAddDTO.getSeckillOrderItemAddDTO().getPrice());
        rabbitTemplate.convertAndSend(RabbitMqComponentConfiguration.SECKILL_EX,RabbitMqComponentConfiguration.SECKILL_RK,success);
        //返回值 属性赋值
        SeckillCommitVO seckillCommitVO = new SeckillCommitVO();
        BeanUtils.copyProperties(orderAddVO,seckillCommitVO);
        return seckillCommitVO;

    }
    //将seckillOrderAddDTO转换为orderAddDTO的方法
    private OrderAddDTO convertSeckillOrderToOrder(SeckillOrderAddDTO seckillOrderAddDTO) {
        //将同名属性赋值到普通订单中
        OrderAddDTO orderAddDTO = new OrderAddDTO();
        BeanUtils.copyProperties(seckillOrderAddDTO,orderAddDTO);

        //将秒杀订单中的SeckillOrderItemAddDTO转换为OrderItemAddDTO存入集合,
        OrderItemAddDTO orderItemAddDTO = new OrderItemAddDTO();
        BeanUtils.copyProperties(seckillOrderAddDTO.getSeckillOrderItemAddDTO(),orderItemAddDTO);

        List<OrderItemAddDTO> list = new ArrayList<>();
        list.add(orderItemAddDTO);
        //将其他属性赋值到普通订单
        orderAddDTO.setOrderItems(list);

        return orderAddDTO;
    }

    //获取上下文的方法
    public CsmallAuthenticationInfo getUserInfo(){
        // 编码获得SpringSecurity上下文中保存的权限
        UsernamePasswordAuthenticationToken authenticationToken =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder
                        .getContext().getAuthentication();
        //判断获得的信息是不是null
        if (authenticationToken == null) {
            throw new CoolSharkServiceException(ResponseCode.UNAUTHORIZED,"请先登录!");
        }
        //上下文信息确定存在后,获取其中的用户信息
        CsmallAuthenticationInfo csmallAuthenticationInfo =
                (CsmallAuthenticationInfo) authenticationToken.getCredentials();
        return csmallAuthenticationInfo;

    }
    //获取用户的id的方法,
    public Long getUserId(){
        return getUserInfo().getId();
    }










}
